package bg.consulting.labo.rtp;

import java.awt.Dimension;
import java.io.File;
import java.net.InetAddress;

import javax.media.Codec;
import javax.media.Control;
import javax.media.Controller;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Owned;
import javax.media.Player;
import javax.media.Processor;
import javax.media.control.QualityControl;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.PushBufferDataSource;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SendStream;
import javax.media.rtp.SessionAddress;

import bg.consulting.labo.util.UtilJMF;

public class BgTransmitRTP {

	private MediaLocator mediaLocatorSource;
	private Processor processor;
	private DataSource dataOutput = null;

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		System.out.println("Test BgTransmit 4");
		BgTransmitRTP t = new BgTransmitRTP();
		t.init();
		System.out.println("Test BgTransmit donne");

	}

	private void init() throws Exception {
		File file = new File("C:\\musique\\test.mp3");
		//File file = new File("C:\\musique\\test.wav");
		System.out.println("File " + file.getAbsolutePath() + "  file.exists :" + file.exists());
		this.mediaLocatorSource = new MediaLocator("" + file.toURI());
		this.createDataSource();
		System.out.println("CreateDAtaSource Done ");
		this.createTransmitter();
		this.processor.start();
	}

	private void createDataSource() throws Exception {

		DataSource ds = Manager.createDataSource(mediaLocatorSource);
		this.processor = Manager.createProcessor(ds);
		this.processor.configure();
		UtilJMF.waitUntil(processor, Processor.Configured, 5000);

		// Set the output content descriptor to RAW_RTP
		// This will limit the supported formats reported from
		// Track.getSupportedFormats to only valid RTP formats.
		ContentDescriptor contentdescriptor = new ContentDescriptor(ContentDescriptor.RAW_RTP);
		processor.setContentDescriptor(contentdescriptor);
		// Realize the processor. This will internally create a flow
		// graph and attempt to create an output datasource for JPEG/RTP
		// audio frames.
		processor.realize();
		UtilJMF.waitUntil(processor, Controller.Realized, 5000);
		// Set the JPEG quality to .5.
		setJPEGQuality(processor, 0.5f);

		// Get the output data source of the processor
		this.dataOutput = processor.getDataOutput();

	}

	private void createTransmitter() throws Exception {

		// create the RTP Manager
		RTPManager rtpManager = RTPManager.newInstance();
		// create the local endpoint for the local interface on
		// any local port
		SessionAddress localAddress = new SessionAddress();

		// initialize the RTPManager
		rtpManager.initialize(localAddress);

		// add the ReceiveStreamListener if you need to receive data
		// and do other application specific stuff
		// ...

		// specify the remote endpoint of this unicast session
		// the address string and port numbers in the following lines
		// need to be replaced with your values.
		InetAddress ipAddress = InetAddress.getByName("192.168.1.10");
		int port = 3000;
		SessionAddress remoteAddress = new SessionAddress(ipAddress, port);
		System.out.println("ipAdresse " + ipAddress + "  " + port);
		// open the connection
		rtpManager.addTarget(remoteAddress);

		// create a send stream for the output data source of a processor
		// and start it
		System.out.println("BgtransmitRTP.DataOutput :" + this.dataOutput);
		// DataSource clone =((SourceCloneable) this.dataOutput).createClone();
		PushBufferDataSource pbds = (PushBufferDataSource) this.dataOutput;
		SendStream sendStream = rtpManager.createSendStream(pbds, 0);
		sendStream.start();

		// send data and do other application specific stuff,
		// ...

		// close the connection if no longer needed.
		// rtpManager.removeTarget( remoteAddress, "client disconnected.");

		// call dispose at the end of the life-cycle of this RTPManager so
		// it is prepared to be garbage-collected.
		// rtpManager.dispose();

	}

	/**
	 * For JPEG and H263, we know that they only work for particular sizes. So
	 * we'll perform extra checking here to make sure they are of the right
	 * sizes.
	 */
	Format checkForVideoSizes(Format original, Format supported) {

		int width, height;
		Dimension size = ((VideoFormat) original).getSize();
		Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
		Format h263Fmt = new Format(VideoFormat.H263_RTP);

		if (supported.matches(jpegFmt)) {
			// For JPEG, make sure width and height are divisible by 8.
			width = (size.width % 8 == 0 ? size.width : (int) (size.width / 8) * 8);
			height = (size.height % 8 == 0 ? size.height : (int) (size.height / 8) * 8);
		} else if (supported.matches(h263Fmt)) {
			// For H.263, we only support some specific sizes.
			if (size.width < 128) {
				width = 128;
				height = 96;
			} else if (size.width < 176) {
				width = 176;
				height = 144;
			} else {
				width = 352;
				height = 288;
			}
		} else {
			// We don't know this particular format. We'll just
			// leave it alone then.
			return supported;
		}

		return (new VideoFormat(null, new Dimension(width, height), Format.NOT_SPECIFIED, null, Format.NOT_SPECIFIED)).intersects(supported);
	}

	/**
	 * Setting the encoding quality to the specified value on the JPEG encoder.
	 * 0.5 is a good default.
	 */
	void setJPEGQuality(Player p, float val) {

		Control cs[] = p.getControls();
		QualityControl qc = null;
		VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG);

		// Loop through the controls to find the Quality control for
		// the JPEG encoder.
		for (int i = 0; i < cs.length; i++) {

			if (cs[i] instanceof QualityControl && cs[i] instanceof Owned) {
				Object owner = ((Owned) cs[i]).getOwner();

				// Check to see if the owner is a Codec.
				// Then check for the output format.
				if (owner instanceof Codec) {
					Format fmts[] = ((Codec) owner).getSupportedOutputFormats(null);
					for (int j = 0; j < fmts.length; j++) {
						if (fmts[j].matches(jpegFmt)) {
							qc = (QualityControl) cs[i];
							qc.setQuality(val);
							System.err.println("- Setting quality to " + val + " on " + qc);
							break;
						}
					}
				}
				if (qc != null)
					break;
			}
		}
	}

}
